﻿#region Disclaimer/Info
///////////////////////////////////////////////////////////////////////////////////////////////////
// MetaCollection
// 
// MetaCollection is a system to provide a standard structure, permissions and metadata service
// for content organization.
//
// This project is hosted at Google Code at http://code.google.com/p/metacollection/
//
// This project is licensed under the BSD license.  See the License.txt file for more information.
///////////////////////////////////////////////////////////////////////////////////////////////////
#endregion

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using MetaCollection.Framework;

namespace MetaCollection.Framework
{
	/// <summary>
	/// A set of flags denoting the different types of events that a component implementing <see cref="IRequestSink"/>
	/// may be advised of on a a <see cref="RequestHandler"/>  Each of these flags corosponds to an event method on the
	/// <see cref="IRequestSink"/> interface.
	/// </summary>
	[Flags]
	public enum RequestEventTypes
	{
		/// <summary>
		/// None
		/// </summary>
		None = 0,
		/// <summary>
		/// First event raised when a <see cref="RequestHandler"/> starts processing a request.
		/// </summary>
		OnRequestStart = 1 << 1,
		/// <summary>
		/// Raised before a <see cref="RequestHandler"/> begins validating a request.
		/// </summary>
		OnBeforeValidateRequest = 1 << 2,
		/// <summary>
		/// Raised when the validation of a request has been completed.
		/// </summary>
		OnRequestValidateComplete = 1 << 3,
		/// <summary>
		/// Raised before the <see cref="RequestHandler"/> begins resolving the path to the Item associated with the request.
		/// </summary>
		OnBeforePathResolve = 1 << 4,
		/// <summary>
		/// Raised when the path to the item associated with the request has been resolved.
		/// </summary>
		OnPathResolveComplete = 1 << 5,
		/// <summary>
		/// Raised before the actions in the request are performed.
		/// </summary>
		OnBeforeInvokeRequest = 1 << 6,
		/// <summary>
		/// Raised when the request is complete but before control is returned from the <see cref="RequestHandler"/>
		/// </summary>
		OnRequestComplete = 1 << 7,
		/// <summary>
		/// Event used to provide request validation for a <see cref="RequestHandler"/>. A subscribing sink will be responsible
		/// for validating the request in the <see cref="ItemContext"/>
		/// </summary>
		OnValidateRequest = 1 << 8,
		/// <summary>
		/// Event used to provide path resolution for a <see cref="RequestHandler"/>.  A subscribing sink will be responsible for 
		/// resolving the path segment provided.
		/// </summary>
		OnPathResolve = 1 << 9,
		/// <summary>
		/// Event used to provide Item metadata for a request.  A subscribing sink will be responsible for ensuring that the 
		/// <see cref="ItemContext"/> has the proper Item metadata complete when this event is raised.
		/// </summary>
		OnProvideItem = 1 << 10,
		/// <summary>
		/// Event used to provide Item Resource data for a request.  A subscribing sink will be responsible for ensuring that the 
		/// <see cref="ItemContext"/> has the proper Item resource data provided when this event is raised.
		/// </summary>
		OnProvideResource = 1 << 11,
		/// <summary>
		/// Raised when a <see cref="RequestHandler"/> is disposing.
		/// </summary>
		OnHandlerDisposing = 1 << 12,
		/// <summary>
		/// Events that a provider should subscribe to in order to provide core <see cref="RequestHandler"/> functions.
		/// </summary>
		/// <remarks>OnValidateRequest, OnPathResolve, OnProvideMetadata, OnProvideResource, OnHandlerDisposing</remarks>
		ResourceProviderEvents = OnValidateRequest | OnPathResolve | OnProvideItem | OnProvideResource | OnHandlerDisposing,

		/// <summary>
		/// <see cref="RequestHandler"/> pipeline stage notifications
		/// </summary>
		NotificationEvents = OnRequestStart | OnBeforeValidateRequest | OnRequestValidateComplete | OnBeforePathResolve |
			OnPathResolveComplete | OnBeforeInvokeRequest | OnRequestComplete | OnHandlerDisposing,
		/// <summary>
		/// All event types
		/// </summary>
		AllEvents = ResourceProviderEvents | NotificationEvents
	}

	/// <summary>
	/// An extension method for getting an enumerator for a instance of <see cref="RequestEventTypes"/>
	/// </summary>
	public static class RequestEventTypeExtensions
	{
		/// <summary>
		/// Gets an enumerator for a instance of <see cref="RequestEventTypes"/>
		/// </summary>
		/// <param name="requestEvent">The request event type instance.</param>
		/// <returns>an ienumberable of RequestEventTypes</returns>
		public static IEnumerable<RequestEventTypes> GetEnumerator(this RequestEventTypes requestEvent)
		{
			if (requestEvent == RequestEventTypes.None)
				yield break;
			if ((requestEvent & RequestEventTypes.OnRequestStart) == RequestEventTypes.OnRequestStart)
				yield return RequestEventTypes.OnRequestStart;
			if ((requestEvent & RequestEventTypes.OnBeforePathResolve) == RequestEventTypes.OnBeforePathResolve)
				yield return RequestEventTypes.OnBeforePathResolve;
			if ((requestEvent & RequestEventTypes.OnPathResolve) == RequestEventTypes.OnPathResolve)
				yield return RequestEventTypes.OnPathResolve;
			if ((requestEvent & RequestEventTypes.OnPathResolveComplete) == RequestEventTypes.OnPathResolveComplete)
				yield return RequestEventTypes.OnPathResolveComplete;
			if ((requestEvent & RequestEventTypes.OnBeforeValidateRequest) == RequestEventTypes.OnBeforeValidateRequest)
				yield return RequestEventTypes.OnBeforeValidateRequest;
			if ((requestEvent & RequestEventTypes.OnValidateRequest) == RequestEventTypes.OnValidateRequest)
				yield return RequestEventTypes.OnValidateRequest;
			if ((requestEvent & RequestEventTypes.OnRequestValidateComplete) == RequestEventTypes.OnRequestValidateComplete)
				yield return RequestEventTypes.OnRequestValidateComplete;
			if ((requestEvent & RequestEventTypes.OnBeforeInvokeRequest) == RequestEventTypes.OnBeforeInvokeRequest)
				yield return RequestEventTypes.OnBeforeInvokeRequest;
			if ((requestEvent & RequestEventTypes.OnProvideItem) == RequestEventTypes.OnProvideItem)
				yield return RequestEventTypes.OnProvideItem;
			if ((requestEvent & RequestEventTypes.OnProvideResource) == RequestEventTypes.OnProvideResource)
				yield return RequestEventTypes.OnProvideResource;
			if ((requestEvent & RequestEventTypes.OnRequestComplete) == RequestEventTypes.OnRequestComplete)
				yield return RequestEventTypes.OnRequestComplete;
			if ((requestEvent & RequestEventTypes.OnHandlerDisposing) == RequestEventTypes.OnHandlerDisposing)
				yield return RequestEventTypes.OnHandlerDisposing;
			yield break;
		}

		/// <summary>
		/// Gets the event handler.
		/// </summary>
		/// <remarks>This is the mapping between the RequestEventTypes and the IRequestSink.  If the </remarks>
		/// <param name="requestEvent">The request event.</param>
		/// <param name="sink">The sink.</param>
		/// <returns>The EventHandler on the IRequestSink for the given event type.</returns>
		[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA2204:Literals should be spelled correctly", MessageId = "RequestEventType", Justification = "It is spelled correctly.")]
		[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA2204:Literals should be spelled correctly", MessageId = "IRequestSink", Justification = "It is spelled correctly.")]
		public static EventHandler<EventArgs> GetEventHandler(this RequestEventTypes requestEvent, IRequestSink sink)
		{
			EventHandler<EventArgs> handler = null;
			if ((requestEvent & RequestEventTypes.OnRequestStart) == RequestEventTypes.OnRequestStart)
				handler = new EventHandler<EventArgs>(sink.OnRequestStart);
			else if ((requestEvent & RequestEventTypes.OnBeforeValidateRequest) == RequestEventTypes.OnBeforeValidateRequest)
				handler = new EventHandler<EventArgs>(sink.OnBeforeValidateRequest);
			else if ((requestEvent & RequestEventTypes.OnValidateRequest) == RequestEventTypes.OnValidateRequest)
				handler = new EventHandler<EventArgs>(sink.OnValidateRequest);
			else if ((requestEvent & RequestEventTypes.OnRequestValidateComplete) == RequestEventTypes.OnRequestValidateComplete)
				handler = new EventHandler<EventArgs>(sink.OnRequestValidateComplete);
			else if ((requestEvent & RequestEventTypes.OnBeforePathResolve) == RequestEventTypes.OnBeforePathResolve)
				handler = new EventHandler<EventArgs>(sink.OnBeforePathResolve);
			else if ((requestEvent & RequestEventTypes.OnPathResolve) == RequestEventTypes.OnPathResolve)
				handler = new EventHandler<EventArgs>(sink.OnPathResolve);
			else if ((requestEvent & RequestEventTypes.OnPathResolveComplete) == RequestEventTypes.OnPathResolveComplete)
				handler = new EventHandler<EventArgs>(sink.OnPathResolveComplete);
			else if ((requestEvent & RequestEventTypes.OnBeforeInvokeRequest) == RequestEventTypes.OnBeforeInvokeRequest)
				handler = new EventHandler<EventArgs>(sink.OnBeforeInvokeRequest);
			else if ((requestEvent & RequestEventTypes.OnProvideItem) == RequestEventTypes.OnProvideItem)
				handler = new EventHandler<EventArgs>(sink.OnProvideItem);
			else if ((requestEvent & RequestEventTypes.OnProvideResource) == RequestEventTypes.OnProvideResource)
				handler = new EventHandler<EventArgs>(sink.OnProvideResource);
			else if ((requestEvent & RequestEventTypes.OnRequestComplete) == RequestEventTypes.OnRequestComplete)
				handler = new EventHandler<EventArgs>(sink.OnRequestComplete);
			else if ((requestEvent & RequestEventTypes.OnHandlerDisposing) == RequestEventTypes.OnHandlerDisposing)
				handler = new EventHandler<EventArgs>(sink.OnHandlerDisposing);
			else
				throw new InvalidOperationException("Unsupported RequestEventType in IRequestSink");
			return handler;
		}
	}
}
